这篇文章我将接着节讲述关于 SDWebImage 图片下载后处理方式,缓存进行讲解。
经过上面我们可以知道 SDWebImage 是可以从远程的服务器加载图片,然后在UIImageView 上进行显示。但是你有想过 SDWebImage 到底是什么呢?
在使用时我们知道需要导入包:UIImageView+WebCache.h 我们可以根据这看出 SDWebImage 是一个 UIImageView 的分类,使用 Category 进行分装的类。下面列出 SDWebImage 可以实现的功能:
- 提供
UIImageView的一个分类,可以对图片进行异步加载和缓存管理 - 一步内存 & 磁盘管理 & 自动对过期的缓存进行相关的处理
- 一个一步图片的加载器
- 支持
GIF的图片加载 - 后台对图片进行解压处理
- 确保同意
URL的图片不会被数次加载 - 确保虚假的
URL不会被反复加载 - 确保下载和缓存时主线程不会被阻塞
- 优良使用性能
- 采用
GCD可以采用并行处理,iOS 5.0的ARC自动计数原则 - 支持
Arm64(64位CPU处理)
本篇博客是在 SDWebImage 的图片加载基础之上进行探索,下面我们就来看下 SDWebImage 是如何实现对图片实行缓存处理。
实例
SDImageCache 是图片下载后内存缓存管理和磁盘缓存管理的类,不过还是我们最常见的单例模式 sharedImageCache 来进行得到实例。默认的缓存空间上是 default ,如果自己看着不怎么好的话可以自己进行相关的空间申请。下面是 SDWebCache 的简介:
1 | + (SDImageCache *)sharedImageCache { |
这里使用 dispatch_once 的形式每次开启一个线程,这样可以防止多个单例进行同时的初始化。
1 | - (id)init { |
上面我们可以看出在我们使用
init来进行初始化缓存空间,紧接着就调用 initWithNamespace: & initWithNamespace: diskCacheDirectory:来进一步对磁盘进行缓存空间的初始化。
内存缓存类
1 | @interface AutoPurgeCache : NSCache |
上面我们可以看出在缓存过程中我们采用的是 NSCache 的子类 AutoPurgeCache 进行线管的缓存处理,但是我们也可以直接使用 NSdictionary 来进行处理,为什么不使用呢?后面我将会讲出😸。返回上面,我们可以看出在缓存时我们采用注册和监听的模式对缓存的内存监听,一旦缓存数据达到临界点就要条用 removeAllObjects。这里有关于方法在运行时编译情况下的过程。
在缓存过程中我们使用的是
NSCache而不是用NSDictionary呢,下面我们看下NSCache的优点:
- 自动删减功能
- 线程安全
- 不会拷贝健
基于上面
NSCache 的特点选着使用 NSCache 是更加易于对缓存的管理
缓存在APP周期的设置
在应用开发对内容缓存的过程我们也可以参考下面缓存的处理机制,这也对我们 App 的性能会有比较大的提升。下面按照 App 的分为:内存警告、程序终止和后台三种情况实现缓存策略。
内存警告
在我们使用 SDWebImage 过程时程序一直都会对我们访的图片进行相关缓存处理,但是当我们缓存较大时就会产生警告
1 | - (void)clearMemory { |
上面是我们注册发现内存过大需要调用的方法。
程序终止
1 | - (void)cleanDisk { |
从上面我们可以看出当收到 UIApplicationWillTerminateNotification 时,SDImageCache 将会使用 ioQueue 异步地清理磁盘缓存。
清除过程的逻辑如下:
先清除已超过最大缓存时间的缓存文件(最大缓存时间默认为一星期)
在第一轮清除的过程中保存文件属性,特别是缓存文件大小
在第一轮清除后,如果设置了最大缓存并且保留下来的磁盘缓存文件仍然超过了配置的最大缓存,那么进行第二轮以大小为基础的清除。
首先删除最老的文件,直到达到期望的总的缓存大小,即最大缓存的一半。
程序进入后台
1 | - (void)backgroundCleanDisk { |
当收到 UIApplicationDidEnterBackgroundNotification 时,在手机系统后台进行如上面描述的异步磁盘缓存清理。这里利用 Objective-C 的动态语言特性,得到UIApplication 的单例 sharedApplication ,使用 sharedApplication 开启后台任务 cleanDiskWithCompletionBlock:
查询图片
1 | - (NSOperation *)queryDiskCacheForKey:(NSString *)key done:( SDWebImageQueryCompletedBlock)doneBlock { |
查询缓存,默认使用方法 queryDiskCacheForKey:done:,如果此方法返回nil,则说明缓存中现在还没有这张照片,因此你需要得到并缓存这张图片。缓存 key 是缓存图片的程序唯一的标识符,一般使用图片的完整 URL。
如果不想 SDImageCache 查询磁盘缓存,你可以调用另一个方法:imageFromMemoryCacheForKey:。
返回值为 NSOpration,单独使用 SDImageCache 没用,但是使用 SDWebImageManager 就可以对多个任务的优先级、依赖,并且可以取消。
自定义@autoreleasepool,autoreleasepool代码段里面有大量的内存消耗操作,自定义autoreleasepool可以及时地释放掉内存。
1 | - (NSString *)cachePathForKey:(NSString *)key inPath:(NSString *)path { |
上面代码段是从磁盘获取图片的代码。得到图片对应的
UIData后,还要经过如下步骤,才能返回对应的图片:
- 根据图片的不同种类,生成对应的
UIImage- 根据
key值,调整image的scale值- 如果设置图片需要解压缩,则还需对
UIImage进行解码
下面是MD5的加密方式
1 | - (NSString *)cachedFileNameForKey:(NSString *)key { |
图片的保存
1 | - (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk { |
存储一个图片到缓存中,可以使用方法
storeImage:forKey:method:,默认,图片既会存储到内存缓存中,也会异步地保存到磁盘缓存中。
如果只想使用内存缓存,可以使用另外一个方法storeImage:forKey:toDisk,第三个参数传入false值就好了。